package cn.rxmind.dlicense.core.manager;

import cn.rxmind.dlicense.core.base.LicenseManagerWrapper;
import cn.rxmind.dlicense.core.base.DLicenseContent;

import cn.rxmind.dlicense.core.constants.CheckRuleEnum;
import cn.rxmind.dlicense.core.event.DLicenseEvent;
import cn.rxmind.dlicense.core.event.DLicenseEventListener;
import cn.rxmind.dlicense.core.event.DLicenseEventPublisher;
import cn.rxmind.dlicense.core.factory.DLicenseParamFactory;
import cn.rxmind.dlicense.core.utils.AssertUtil;
import cn.rxmind.dlicense.core.validator.LicenseActiveTimeValidator;
import cn.rxmind.dlicense.core.validator.DLicenseValidator;
import cn.rxmind.dlicense.core.validator.DLicenseValidatorList;
import de.schlichtherle.license.LicenseParam;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 *
 *
 * @author renxin
 * @email renxinzhiliangzhi@163.com
 * @date 2021/4/22 9:57 上午
 */
public abstract class AbstractClientLicenseManager implements DClientLicenseManager, DLicenseEventPublisher {

    protected final LicenseManagerWrapper licenseManagerWrapper;

    protected final ApplicationEventPublisher applicationEventPublisher;

    private final Executor publishExecutor;

    private final Set<DLicenseEventListener> listeners;

    protected final DLicenseContent dLicenseContent;

    protected final DLicenseValidatorList<DLicenseValidator> validatorList = new DLicenseValidatorList<>();

    public AbstractClientLicenseManager(ApplicationEventPublisher applicationEventPublisher,
                                        Supplier<byte[]> licenseBytesReader) {
        this.applicationEventPublisher = applicationEventPublisher;
        LicenseParam licenseParam = DLicenseParamFactory.createLicenseParam4Client();
        AssertUtil.assertFalse(licenseBytesReader == null,"licenseBytesReader can not be null");
        this.licenseManagerWrapper = new LicenseManagerWrapper(licenseParam,licenseBytesReader);
        this.dLicenseContent = licenseInstall();
        this.validatorList.addValidators(new LicenseActiveTimeValidator());
        configValidatorsByLicenseContent();
        // 事件发布器线程池
        this.publishExecutor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(), r -> {
            Thread thread = new Thread(r);
            thread.setName("License publish thread");
            return thread;
        });
        // 事件监听器
        this.listeners = new HashSet<>();
        // 注入事件发布器
        this.validatorList.forEach(validator -> validator.setPublisher(this));
    }

    @Override
    public void addListener(DLicenseEventListener listener) {
        this.listeners.add(listener);
    }

    @Override
    public void publish(final DLicenseEvent event) {
        // 如果使用了Spring事件，就使用spring事件发布器发布
        publishExecutor.execute(()-> {
            if(event instanceof ApplicationEvent){
                this.applicationEventPublisher.publishEvent((ApplicationEvent) event);
            }else {
                listeners.forEach(listener -> listener.onEvent(event));
            }
        });
    }

    /**
     * 初始化操作方法，证书安装完成后被调用，
     * 子类可借助spring bean的生命周期等管理器创建完后启动
     * 也可以通过某种事件监听机制触发
     */
    @Override
    public abstract void start();

    /**
     * 按顺序执行校验器
     */
    protected void validateByOrder(){
        this.validatorList.validateByOrder(this.dLicenseContent);
    }

    @Override
    public DLicenseContent getDLicenseContent() {
        return this.dLicenseContent;
    }

    @Override
    public DLicenseContent licenseInstall() {

        try {
            return licenseManagerWrapper.install();
        }catch (Exception e){
            System.err.printf("证书安装失败: %s%n",e.getMessage());
            System.exit(-1);
            return new DLicenseContent();
        }
    }

    @Override
    public void addValidator(DLicenseValidator... validators) {
        this.validatorList.addValidators(validators);
    }

    /**
     * 根据证书内容添加校验器
     */
    private void configValidatorsByLicenseContent(){
        this.dLicenseContent.getActiveRules().stream()
                .map(CheckRuleEnum::mappingValidator)
                .forEach(this::addValidator);
    }
}
